#include "component.h"
#include <i_component_holder.h>
#include <i_component_container.h>
#include <i_component_factory.h>
#include <algorithm>
#include <iterator>

CComponent::CComponent() 
	: m_factory(nullptr), m_comid(0), m_container(nullptr), m_status(ECOMPONENT_STATUS_DEAD), m_dependences(new IComponentHolderPtrSet())
{}

CComponent::~CComponent()
{
	if (m_factory != nullptr)
		m_factory->DelInstance(*this);

	delete m_dependences;
}

void CComponent::SetFactory(CComponentFactory& factory)
{
	if (m_factory != nullptr)
		m_factory->DelInstance(*this);

	m_factory = &factory;
	m_factory->AddInstance(*this);
}

CComponentFactory* CComponent::GetFactory()
{
	return m_factory;
}

IComponentContainer* CComponent::GetContainer()
{
	return m_container;
}

int CComponent::Install(IComponentContainer& container, ComID com_id)
{
	m_comid = com_id;
	m_container = &container;
	for (auto dep : *m_dependences)
		m_container->Register(*dep);

	return this->_OnInstall();
}

void CComponent::Uninstall()
{
	for (auto dep : *m_dependences)
		m_container->Unregister(*dep);

	return this->_OnUninstall();
}

int CComponent::Start()
{
	m_status = ECOMPONENT_STATUS_STARTING;
	for (auto com_holder : *m_dependences)
	{
		auto com_ptr = com_holder->GetComponent();
		if (com_ptr == NULL)
			return ECOMPONENT_REQUIRE_DEP;

		auto com_flags = com_holder->GetFlags();
		if (com_flags.test(EHOLDER_FLAGS_DEPENDENCE) && com_ptr->GetStatus() != ECOMPONENT_STATUS_RUNNING)
			return ECOMPONENT_WAIT;
	}

	int ret = _OnStart();
	if (ret == ECOMPONENT_OK)
		m_status = ECOMPONENT_STATUS_RUNNING;

	return ret;
}

void CComponent::Stop()
{
	m_status = ECOMPONENT_STATUS_STOPPING;
	_OnStop();
	m_status = ECOMPONENT_STATUS_DEAD;
}

int CComponent::_OnInstall()
{
	return ECOMPONENT_OK;
}

void CComponent::_OnUninstall()
{

}

int CComponent::_OnStart()
{
	return ECOMPONENT_OK;
}

void CComponent::_OnStop()
{

}

void CComponent::_AddDependence(const IComponentHolderPtrList& dependences)
{
	std::for_each(dependences.begin(), dependences.end(), [this](IComponentHolder* holder) -> void {
		m_dependences->insert(holder);
	});
}

void CComponent::_AddDependence(IComponentHolder& dependence)
{
	m_dependences->insert(&dependence);
}


